package server.handler;

import io.netty.channel.*;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.websocketx.*;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Lyoto
 * @Description
 * @Date 2022-11-20 13:34
 * @Version
 **/
@Slf4j
public class WebsocketChannelHandler extends SimpleChannelInboundHandler<Object> {
    private static final String WEBSOCKET_PATH = "/ws";
    private WebSocketServerHandshaker handShaker;
    
    private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
        // 处理各种websocket的frame信息
        if (frame instanceof CloseWebSocketFrame) {
            handShaker.close(ctx, (CloseWebSocketFrame) frame.retain());
            return;
        }
        if (frame instanceof TextWebSocketFrame) {
            String msg = ((TextWebSocketFrame) frame).text();
            // 直接返回
            ChannelFuture channelFuture = ctx.writeAndFlush(new TextWebSocketFrame(msg));
            channelFuture.addListener((ChannelFutureListener) (future) -> {
                Channel channel = future.channel();
                if (future.isSuccess()){
                    log.info("发送消息{},客户端{}",msg,channel.remoteAddress().toString());
                }else {
                    log.info("发送消息失败{},客户端{}",msg,channel.remoteAddress().toString());
                }
            });
            return;
        }
        if (frame instanceof BinaryWebSocketFrame) {
            // 直接返回
            ctx.write(frame.retain());
        }
    }
    
    private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
        // 处理异常
        if (!req.decoderResult().isSuccess()) {
            log.info("当前请求有异常 ctx:{},request:{}", ctx, req);
        }
        // websocket握手
        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                getWebSocketLocation(req), null, true, 5 * 1024 * 1024);
        handShaker = wsFactory.newHandshaker(req);
        if (handShaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        } else {
            handShaker.handshake(ctx.channel(), req);
        }
    }
    
    private static String getWebSocketLocation(FullHttpRequest req) {
        String location = req.headers().get(HttpHeaderNames.HOST) + WEBSOCKET_PATH;
        return "ws://" + location;
    }
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 根据消息类型，处理两种不同的消息
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest request = (FullHttpRequest) msg;
            if(!request.headers().get(HttpHeaderNames.CONNECTION).equals(HttpHeaderNames.UPGRADE.toString())){
                WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
                return;
            }
            handleHttpRequest(ctx, request);
        } else if (msg instanceof WebSocketFrame) {
            handleWebSocketFrame(ctx, (WebSocketFrame) msg);
        }
    }
    
}
